#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include "util.hpp"
#include "log.hpp"

// 下载的原始html文件目录 和 处理后的文件目录
const std::string src_path = "data/source_html";
const std::string output = "data/raw_html/raw.txt";

namespace parser_helper
{
    typedef struct DocInfo
    {
        std::string title;   // 文档的标题
        std::string content; // 文档的内容
        std::string url;     // 该文档在官网中的url
    } DocInfo_t;

    bool EnumFile(const std::string &src_path, std::vector<std::string> *files_list) // 获取文件名和路径
    {
        boost::filesystem::path root_path(src_path);
        // 判断路径是否存在
        if (!boost::filesystem::exists(root_path))
        {
            ELOG("%s not exists!", src_path.c_str());
            return false;
        }

        boost::filesystem::recursive_directory_iterator end;
        for (boost::filesystem::recursive_directory_iterator it(root_path); it != end; it++)
        {
            // 判断文件是否是普通文件
            if (!boost::filesystem::is_regular_file(*it))
            {
                continue;
            }
            // 判断文件路径名的后缀是否html
            if (it->path().extension() != ".html")
            {
                continue;
            }
            // std::cout << "debug: " << it->path().string() << std::endl;
            //  将所有带路径的html保存在files_list
            files_list->push_back(it->path().string());
        }
        return true;
    }

    static bool ParseTitle(const std::string &file, std::string *title)
    {
        // 提取标题
        std::size_t begin = file.find("<title>");
        if (begin == std::string::npos)
        {
            return false;
        }
        std::size_t end = file.find("</title>");
        if (end == std::string::npos)
        {
            return false;
        }
        begin += std::string("<title>").size();
        if (begin > end)
        {
            return false;
        }
        *title = file.substr(begin, end - begin);
        return true;
    }
    static bool ParseContent(const std::string &file, std::string *content)
    {
        // 去标签,基于一个简易的状态机
        enum status
        {
            LABLE,
            CONTENT
        };
        enum status s = LABLE;
        for (char c : file)
        {
            switch (s)
            {
            case LABLE:
                if (c == '>')
                    s = CONTENT;
                break;
            case CONTENT:
                if (c == '<')
                    s = LABLE;
                else
                {
                    // 不保留原始文件中的\n，\n用作解析后的每个文件文本间的分隔符
                    if (c == '\n')
                        c = ' ';
                    content->push_back(c);
                }
                break;
            default:
                return false;
            }
        }
        return true;
    }
    static bool ParseUrl(const std::string &file_path, std::string *url)
    {
        // 构建URL
        std::string url_head = "https://www.boost.org/doc/libs/1_88_0/doc/html";
        std::string url_tail = file_path.substr(src_path.size());
        *url = url_head + url_tail;
        return true;
    }
    // for debug
    static void ShowDoc(const DocInfo_t &doc)
    {
        std::cout << "title: " << doc.title << std::endl;
        std::cout << "content: " << doc.content << std::endl;
        std::cout << "url: " << doc.url << std::endl;
    }

    bool ParseHtml(const std::vector<std::string> &files_list, std::vector<DocInfo_t> *results) // 解析文件内容
    {
        for (const std::string &file : files_list)
        {
            // 1.read()读取文件
            std::string result;
            if (!util::FileUtil::ReadFile(file, &result))
            {
                ELOG("read file error");
                continue;
            }
            DocInfo_t doc;
            // 2.解析文件，提取title
            if (!ParseTitle(result, &doc.title))
            {
                ELOG("parse title error");
                continue;
            }
            // 3.解析文件，去标签
            if (!ParseContent(result, &doc.content))
            {
                ELOG("parse content error");
                continue;
            }
            // 4. 解析文件路径，构建url
            if (!ParseUrl(file, &doc.url))
            {
                ELOG("parse url error");
                continue;
            }
            // done,完成了解析任务,当前文档的相关结果都保存在了doc里面
            // parser_helper::ShowDoc(doc);// for debug
            results->push_back(std::move(doc)); // 使用move减少拷贝
        }
        return true;
    }
    bool SaveHtml(const std::vector<DocInfo_t> &results, const std::string &output)
    {
        #define SEP '\3'
        // 按照二进制方式进行写入
        std::ofstream out(output, std::ios::out | std::ios::binary);
        if (!out.is_open())
        {
            ELOG("open %s failed!", output.c_str());
            return false;
        }
        // 就可以进行文件内容的写入了
        std::size_t count = 0;//for debug
        for (auto &item : results)
        {
            std::string out_string;
            out_string = item.title;
            out_string += SEP;
            out_string += item.content;
            out_string += SEP;
            out_string += item.url;
            out_string += '\n';
            out.write(out_string.c_str(), out_string.size());
            std::cout << "Parse Html: "<< ++count <<", Done "<< std::endl;//for debug
        }
        out.close();
        return true;
    }
}